package com.hoppinzq.service.ftp;

import org.apache.commons.io.IOUtils;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.stereotype.Component;

import java.io.*;
import java.math.BigDecimal;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author:ZhangQi
 **/
@Component
public class FtpUtil {

    /**
     * 删除文件
     * @param client
     * @param pathname
     * @param filename
     * @return
     */
    public boolean deleteFile(FTPClient client , String pathname, String filename){
        boolean flag = false;
        try {
            client.changeWorkingDirectory(pathname);
            client.dele(filename);
            client.logout();
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 上传文件
     * @param ftpPath  ftp文件存放物理路径
     * @param fileName 文件路径
     * @param input 文件输入流，即从本地服务器读取文件的IO输入流
     */
    public static void uploadFile(FTPClient client ,String ftpPath, String fileName,InputStream input) throws Exception{
        client.makeDirectory(ftpPath);
        client.changeWorkingDirectory(ftpPath);
        client.setFileType(FTP.BINARY_FILE_TYPE);
        fileName=new String(fileName.getBytes("GBK"),"iso-8859-1");
        client.storeFile(fileName, input);
        input.close();
    }

    /**
     * 判断是否存在指定的文件（上传时先调用这个方法判断是否有重名文件）
     * @param ftpClient
     * @param path
     * @return
     * @throws IOException
     */
    public boolean existFile(FTPClient ftpClient,String path) throws IOException {
        boolean flag = false;
        FTPFile[] ftpFileArr = ftpClient.listFiles(path);
        if (ftpFileArr.length > 0) {
            flag = true;
        }
        return flag;
    }

    /**
     * 文件重命名/文件移动
     * @param ftpClient
     * @param from ftp服务器上的文件名/文件夹名
     * @param to 重名名（全路径，不加路径会重命名后移动至/下）
     * @throws Exception
     */
    public static void rename(FTPClient ftpClient,String from,String to) throws IOException, Exception{
        ftpClient.rename(from,to);
    }

    /**
     * 获取文件列表
     * @param ftpClient
     * @param dir 目录
     * @return
     * @throws Exception
     */
    public static List getFileList(FTPClient ftpClient,String dir,String ip) throws Exception{
//        FTPListParseEngine engine = ftpClient.initiateListParsing("/");
//        while (engine.hasNext()) {
//            FTPFile[] files = engine.getNext(2);  //一次查两条
//        }
        FTPFile[] files = ftpClient.listFiles(dir);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        List fileList=new ArrayList();
        for(int i=0;i<files.length;i++){
            FTPFile file=files[i];
            Map fileMap=new HashMap();
            String fileName=file.getName();
            if(file.getType()==0){
                fileMap.put("isDir",false);
                if(fileName.indexOf(".")==-1){
                    fileMap.put("type","file");
                }else{
                    fileMap.put("type",fileName.substring(fileName.lastIndexOf(".")+1));
                    fileMap.put("url","ftp://"+ip+"/"+fileName);
                }
            }else{
                fileMap.put("isDir",true);
                fileMap.put("type","dir");
            }
            fileMap.put("name",fileName);
            fileMap.put("fileSize",getSize(file.getSize()));
            fileMap.put("fileGroup",file.getGroup());
            fileMap.put("fileHardLinkCount",file.getHardLinkCount());
            fileMap.put("fileLink",file.getLink());
            fileMap.put("fileRawListing",file.getRawListing());
            fileMap.put("updateTime",sdf.format(file.getTimestamp().getTime()));
            fileMap.put("fileUser",file.getUser());
            fileList.add(fileMap);
        }
        return fileList;
    }

    /**
     * 文件大小转换字符串
     * @param size
     * @return
     */
    private static String getSize(long size){
        String units = "B";
        float _size=size;
        if(_size/1024>=1){
            _size = _size/1024;
            units = "KB";
        }
        if(_size/1024>=1){
            _size = _size/1024;
            units = "MB";
        }
        return new BigDecimal(_size).setScale(2,BigDecimal.ROUND_HALF_UP) + units;
    }

    /**
     * 下载ftp服务器文件方法
     *
     * @param ftpClient   FTPClient对象
     * @param newFileName 新文件名
     * @param fileName    原文件（路径＋文件名）
     * @param downUrl     下载路径
     * @return
     * @throws IOException
     */
    public static boolean downFile(FTPClient ftpClient, String newFileName, String fileName, String downUrl) throws IOException {
        boolean isTrue = false;
        OutputStream os = null;
        File localFile = new File(downUrl + "/" + newFileName);
        if (!localFile.getParentFile().exists()) {//文件夹目录不存在创建目录
            localFile.getParentFile().mkdirs();
            localFile.createNewFile();
        }
        os = new FileOutputStream(localFile);
        isTrue = ftpClient.retrieveFile(new String(fileName.getBytes(), "ISO-8859-1"), os);
        os.close();
        return isTrue;
    }

    /**
     * 断开FTP服务器连接
     *
     * @param ftpClient 初始化的对象
     * @throws IOException
     */
    public static void close(FTPClient ftpClient) throws IOException {
        if (ftpClient != null && ftpClient.isConnected()) {
            ftpClient.logout();
            ftpClient.disconnect();
        }
    }

    /**
     * 连接ftp服务器
     *
     * @param ip       ftp地址
     * @param port     端口
     * @param username 账号
     * @param password 密码
     * @return
     * @throws IOException
     */
    public static FTPClient ftpConnection(String ip, String port, String username, String password) throws IOException {
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient.connect(ip, Integer.parseInt(port));
            ftpClient.login(username, password);
            int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                ftpClient.disconnect();
                System.err.println("ftp连接失败");
            }
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ftpClient;
    }


    /**
     *
     * @param myFTP
     * @return
     * @throws IOException
     */
    public static FTPClient ftpConnection(MyFTP myFTP) throws IOException {
        FTPClient ftpClient = new FTPClient();
        try {
            ftpClient.connect(myFTP.getIp(), Integer.parseInt(myFTP.getPort()));
            ftpClient.login(myFTP.getUsername(), myFTP.getPassword());
            int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                ftpClient.disconnect();
                System.err.println("ftp连接失败");
            }
            ftpClient.enterLocalPassiveMode();
            ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ftpClient;
    }

    /**
     * 获取ftp上文件的InputStream
     * @param ftpDirName ftp文件夹名称
     * @param ftpFileName ftp文件名称
     * @return
     */
    public byte[] getInputStream(FTPClient ftp,String ftpDirName, String ftpFileName) {
        try {
            if ("".equals(ftpDirName)) {
                ftpDirName = "/";
            }
            String dir = new String(ftpDirName.getBytes("GBK"), "iso-8859-1");
            if (!ftp.changeWorkingDirectory(dir)) {
                return null;
            }
            // 一定要加上字符集指定，因为获取文件时有中文，会出现乱码而获取不到。
            String fileName = new String(ftpFileName.getBytes("GBK"), "iso-8859-1");
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            // 每次数据连接之前，ftp client告诉ftp server开通一个端口来传输数据，ftp server可能每次开启不同的端口来传输数据，
            // 但是在Linux上，由于安全限制，可能某些端口没有开启，所以就出现阻塞。
            ftp.enterLocalPassiveMode();
            InputStream inputStream = ftp.retrieveFileStream(fileName);
            byte[] bytes = IOUtils.toByteArray(inputStream);
            if (inputStream != null) {
                inputStream.close();
            }
            ftp.getReply();
            ftp.logout();
            return bytes;
        } catch (Exception e) {
            return null;
        }
    }
}

